#include "pch.hpp"
#include "VideoAdapter.hpp"
#include "VideoDeviceID.hpp"




const NVIDIA_DEVICE_ID NVIDIADevices[] = {
	#include "DeviceIDs/NVIDIA_Device_IDs"
};

const ATI_DEVICE_ID ATIDevices[] = {
	#include "DeviceIDs/ATI_Device_IDs"
};

const MATROX_DEVICE_ID MATROXDevices[] = {
	#include "DeviceIDs/MATROX_Device_IDs"
};




const float aspect_4_to_3 = 4.0f / 3;
const float aspect_16_to_9 = 16.0f / 9;
const float aspect_16_to_10 = 16.0f / 10;


DisplayMode::DisplayMode()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

DisplayMode::DisplayMode(uint32 width, uint32 height, WindowMode::Type windowMode, std::pair<int,int> refreshRate)
	: width(width)
	, height(height)
	, refreshRate(refreshRate)
	, windowMode(windowMode)
{
	float aspct = static_cast<float>(width) / height;

	if(aspct == aspect_4_to_3)
		aspect = Aspect4_to_3;
	else if(aspct == aspect_16_to_9)
		aspect = Aspect16_to_9;
	else if(aspct == aspect_16_to_10)
		aspect = Aspect16_to_10;
	else
		aspect = AspectCustom;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

float DisplayMode::aspectRatio() const
{
	return 1.0f * width / height;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool DisplayMode::operator==(const DisplayMode& that) const
{
	return width == that.width &&
		   height == that.height &&
		   aspect == that.aspect &&
		   refreshRate == that.refreshRate &&
		   windowMode == that.windowMode;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




VideoAdapter::VideoAdapter()
	: index(0)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

VideoAdapter::VideoAdapter(uint32 adapterID, uint32 vendorID, uint32 index)
	: name("Unknown")
	, vendor("Unknown")
	, adapterID(adapterID)
	, vendorID(vendorID)
	, index(index)
{
	if(vendorID == 0x10DE)
	{
		std::size_t i = 0;
		vendor = "NVIDIA";

		while(NVIDIADevices[ i ].name)
		{
			if(NVIDIADevices[ i ].ID == adapterID)
			{
				name = NVIDIADevices[ i ].name;
				break;
			}
			++i;
		}
	}
	else if(vendorID == 0x1002)
	{
		std::size_t i = 0;
		vendor = "ATI";

		while(ATIDevices[ i ].name)
		{
			if(ATIDevices[ i ].ID == adapterID)
			{
				name = ATIDevices[ i ].name;
				break;
			}
			++i;
		}
	}
	else if(vendorID == 0x102B)
	{
		std::size_t i = 0;
		vendor = "Matrox";

		while(MATROXDevices[ i ].name)
		{
			if(MATROXDevices[ i ].ID == adapterID)
			{
				name = MATROXDevices[ i ].name;
				break;
			}
			++i;
		}
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////




bool VideoAdapter::supports(const DisplayMode& mode) const
{
	// Any display mode is supported when windowed...
	// The only problem is with custom resolutions that are not supported
	// by the adapter
	if(mode.windowMode == WindowMode::Windowed)
		return true;

	foreach(const DisplayMode& m, modes)
	{
		if(mode == m)
			return true;
	}

	return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

DisplayMode VideoAdapter::greatestDisplayMode() const
{
	boost::optional<DisplayMode> mode;

	foreach(const DisplayMode& displayMode, modes)
	{
		if(!mode || (displayMode.width * displayMode.height) > (mode->width * mode->height))
		{
			mode = displayMode;
		}
	}

	if(!mode)
		BOOSTEXT_THROW(exception("There is not a single DisplayMode available"));

	return mode.get();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

VideoAdapter::DisplayModes VideoAdapter::displayModes4_to_3() const
{
	DisplayModes tmp;
	foreach(const DisplayMode& mode, modes)
	{
		if(mode.aspect == Aspect4_to_3)
			tmp.push_back(mode);
	}

	return tmp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

VideoAdapter::DisplayModes VideoAdapter::displayModes16_to_9() const
{
	DisplayModes tmp;
	foreach(const DisplayMode& mode, modes)
	{
		if(mode.aspect == Aspect16_to_9)
			tmp.push_back(mode);
	}

	return tmp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

VideoAdapter::DisplayModes VideoAdapter::displayModes16_to_10() const
{
	DisplayModes tmp;
	foreach(const DisplayMode& mode, modes)
	{
		if(mode.aspect == Aspect16_to_10)
			tmp.push_back(mode);
	}

	return tmp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
